package com.htu.courseService.websocket.config;
import com.htu.courseService.websocket.facotry.SocketHandlerFactory;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

/**
 * Created By JNNarrator on 2025/01/20 16:08
 * email: jiangn09@chinatelecom.cn
 */
@Component
@ChannelHandler.Sharable
@RequiredArgsConstructor
@Slf4j
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
	private final SocketHandlerFactory socketHandlerFactory;
	
	/**
	 * 一旦连接，第一个被执行
	 */
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		log.info("有新的客户端链接：[{}]", ctx.channel().id().asLongText());
		// 添加到channelGroup 通道组
		NettyConfig.getChannelGroup().add(ctx.channel());
	}
	
	/**
	 * 读取数据
	 */
	@Override
	@SuppressWarnings("unchecked")
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
		log.info("服务器收到消息：{}", msg.text());
		SocketMsg<?> socketMsg = SocketMsg.parse(msg.text());
		try {
			socketHandlerFactory
					.getAppFactory(socketMsg.getApp())
					.getHandler(socketMsg.getOperation())
					.handle(socketMsg,ctx);
		}catch (Exception e){
			e.printStackTrace();
			socketHandlerFactory
					.getAppFactory("system")
					.getHandler("exception")
					.handle(socketMsg,ctx);
		}
	}
	
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		log.info("用户下线了:{}", ctx.channel().id().asLongText());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		log.info("异常：{}", cause.getMessage());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
		ctx.close();
	}
	
	/**
	 * 删除用户与channel的对应关系
	 */
	private void removeUserId(ChannelHandlerContext ctx) {
		AttributeKey<String> key = AttributeKey.valueOf("userId");
		String userId = ctx.channel().attr(key).get();
		if (StringUtils.isNotEmpty(userId)){
			NettyConfig.getChannelMap().remove(userId);
		}
	}
}

